using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;

namespace LS
{
    public enum EntityIdTypeEnum: byte
    {
        SelectionEntity
    }

    public class EntityIdType
    {
        private static SequentialIdCreater typeIdCreater = new SequentialIdCreater() { current = 256 };
        private static List<SequentialIdCreater> s_IdManager = new List<SequentialIdCreater>();
        private static Dictionary<string, SequentialIdCreater> s_IdManagerNameMap = new Dictionary<string, SequentialIdCreater>();
        private static Dictionary<int, SequentialIdCreater> s_IdManagerTypeIdMap = new Dictionary<int, SequentialIdCreater>();

        static EntityIdType()
        {
            string[] names = Enum.GetNames(typeof(EntityIdTypeEnum));
            for (int i = 0; i < names.Length; i++)
            {
                int id = i;
                var creater = CreateIdCreater(names[i], id);
                RegistCreater(creater);
            }
        }

        public static string GetSavesData()
        {
            return new IdTypeDataSerializer().ToJson();
        }

        public static void CoverSavesData(string json)
        {
            IdTypeDataSerializer.FromJson(json).CoverDatas();
        }

        public static int GetTypeId(string typeName)
        {
            if (s_IdManagerNameMap.TryGetValue(typeName, out var creater))
            {
                return creater.createrId;
            }
            return -1;
        }

        public static string GetTypeName(int typeId)
        {
            if (s_IdManagerTypeIdMap.TryGetValue(typeId, out var creater))
            {
                return creater.name;
            }
            return null;
        }

        public static int GetNextId(string typeName)
        {
            if (!s_IdManagerNameMap.TryGetValue(typeName, out var creater))
            {
                throw new System.Exception($"type name[{typeName}] is not exist!");
            }
            return creater.GetNextId();
        }

        public static int GetNextId(int typeId)
        {
            if (!s_IdManagerTypeIdMap.TryGetValue(typeId, out var creater))
            {
                throw new System.Exception($"type id[{typeId}] is not exist!");
            }
            return creater.GetNextId();
        }

        public static int GetLastId(string typeName)
        {
            if (!s_IdManagerNameMap.TryGetValue(typeName, out var creater))
            {
                throw new System.Exception($"type name[{typeName}] is not exist!");
            }
            return creater.GetLastId();
        }

        public static int GetLastId(int typeId)
        {
            if (!s_IdManagerTypeIdMap.TryGetValue(typeId, out var creater))
            {
                throw new System.Exception($"type id[{typeId}] is not exist!");
            }
            return creater.GetLastId();
        }

        public static int RegistIdType(string typeName)
        {
            if (s_IdManagerNameMap.ContainsKey(typeName))
            {
                throw new System.Exception("Id type name is exist!");
            }

            var creater = CreateIdCreater(typeName, typeIdCreater.GetNextId());
            RegistCreater(creater);
            return creater.createrId;
        }

        public static void UnregistIdType(string typeName)
        {
            if (s_IdManagerNameMap.TryGetValue(typeName, out var creater))
            {
                RemoveCreater(creater);
            }
        }

        public static bool ExistType(string typeName)
        {
            return s_IdManagerNameMap.ContainsKey(typeName);
        }

        public static bool ExistType(int typeId)
        {
            return s_IdManagerTypeIdMap.ContainsKey(typeId);
        }

        private static SequentialIdCreater CreateIdCreater(string typeName,int typeId)
        {
            return new SequentialIdCreater()
            {
                name = typeName,
                createrId = typeId
            };
        }

        private static void RegistCreater(SequentialIdCreater creater)
        {
            s_IdManager.Add(creater);
            s_IdManagerNameMap.Add(creater.name, creater);
            s_IdManagerTypeIdMap.Add(creater.createrId, creater);
        }

        private static void RemoveCreater(SequentialIdCreater creater)
        {
            s_IdManager.Remove(creater);
            s_IdManagerNameMap.Remove(creater.name);
            s_IdManagerTypeIdMap.Remove(creater.createrId);
        }

        [Serializable]
        public class SequentialIdCreater
        {
            public string name = string.Empty;
            public int createrId;
            public int current = 0;

            public int GetNextId()
            {
                return current++;
            }

            public int GetLastId()
            {
                return current - 1;
            }
        }

        [Serializable]
        private class IdTypeDataSerializer
        {
            public SequentialIdCreater typeIdCreater;
            public List<SequentialIdCreater> s_IdManager;

            public string ToJson()
            {
                typeIdCreater = EntityIdType.typeIdCreater;
                s_IdManager = EntityIdType.s_IdManager;
                return JsonUtility.ToJson(this);
            }

            public void CoverDatas()
            {
                EntityIdType.typeIdCreater = this.typeIdCreater;
                EntityIdType.s_IdManager = this.s_IdManager;

                EntityIdType.s_IdManagerNameMap = this.s_IdManager.ToDictionary((c) => c.name);
                EntityIdType.s_IdManagerTypeIdMap = this.s_IdManager.ToDictionary(c => c.createrId);
            }

            public static IdTypeDataSerializer FromJson(string json)
            {
                return JsonUtility.FromJson<IdTypeDataSerializer>(json);
            }
        }
    }
}
